package com.gitee.wsl.common.ui.ext.drawScope

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp


/**
 *
 * DrawScope.drawGridLines is the extension method used to draw the grid lines on any graph
 * @param yBottom : Bottom value for Y-Axis
 * @param top: Top value for Y axis
 * @param xLeft: Total left padding in X-Axis.
 * @param paddingRight : Total right padding.
 * @param scrollOffset : Total scroll offset.
 * @param verticalPointsSize : Total points in the X-Axis.
 * @param xZoom : Total zoom offset.
 * @param xAxisScale: Scale of each point in X-Axis.
 * @param ySteps : Number of steps in y-Axis.
 * @param xAxisStepSize: The size of each X-Axis step.
 * @param gridLines: Data class to handle styling related to grid lines.
 */
fun DrawScope.drawGridLines(
    yBottom: Float,
    top: Float,
    xLeft: Float,
    paddingRight: Dp,
    scrollOffset: Float,
    verticalPointsSize: Int,
    xZoom: Float,
    xAxisScale: Float,
    ySteps: Int,
    xAxisStepSize: Dp,
    gridLines: GridLines
) {
    val availableHeight = yBottom - top
    val steps = ySteps + 1 // Considering 0 as step
    val gridOffset = availableHeight / if (steps > 1) steps - 1 else 1
    // Should start from 1 as we don't consider the XAxis
    if (gridLines.enableHorizontalLines) {
        (1 until steps).forEach {
            val y = yBottom - (it * gridOffset)
            gridLines.drawHorizontalLines(this, xLeft, y, size.width - paddingRight.toPx())
        }
    }
    if (gridLines.enableVerticalLines) {
        var xPos = xLeft - scrollOffset
        (0 until verticalPointsSize).forEach { _ ->
            gridLines.drawVerticalLines(this, xPos, yBottom, top)
            xPos += ((xAxisStepSize.toPx() * (xZoom * xAxisScale)))
        }
    }
}

/**
 * Represents the grid lines for any graph
 * @param color: Defines the color of the grid lines.
 * @param lineWidth: Defines the width of the lines.
 * @param pathEffect optional effect or pattern to apply to the line.
 * @param alpha Opacity to be applied to the path from 0.0f to 1.0f representing.
 * fully transparent to fully opaque respectively.
 * @param colorFilter ColorFilter to apply to the [color] when drawn into the destination.
 * @param blendMode Blending algorithm to be applied to the path when it is drawn.
 * @param enableHorizontalLines False to disable horizontal line else true.
 * @param enableVerticalLines False to disable vertical lines else true.
 * @param drawHorizontalLines Draw param used to draw the horizontal lines with given input params.
 * @param drawVerticalLines Draw param used to draw the vertical lines with given input params.
 */
data class GridLines(
    val color: Color = Color.LightGray,
    val lineWidth: Dp = 1.dp,
    val pathEffect: PathEffect? = null,
    val alpha: Float = 1.0f,
    val colorFilter: ColorFilter? = null,
    val blendMode: BlendMode = DrawScope.DefaultBlendMode,
    val enableHorizontalLines: Boolean = true,
    val enableVerticalLines: Boolean = true,
    val drawHorizontalLines: DrawScope.(Float, Float, Float) -> Unit = { xStart, y, xEnd ->
        drawLine(
            color = color,
            start = Offset(xStart, y),
            end = Offset(xEnd, y),
            strokeWidth = lineWidth.toPx(),
            pathEffect = pathEffect,
            colorFilter = colorFilter,
            blendMode = blendMode
        )
    },
    val drawVerticalLines: DrawScope.(Float, Float, Float) -> Unit = { x, yStart, yEnd ->
        drawLine(
            color = color,
            start = Offset(x, yStart),
            end = Offset(x, yEnd),
            strokeWidth = lineWidth.toPx(),
            pathEffect = pathEffect,
            colorFilter = colorFilter,
            blendMode = blendMode
        )
    }
)


/**
 * Draw grid that is divided by 2 vertical and 2 horizontal lines for overlay
 */
fun DrawScope.drawGrid(rect: Rect, strokeWidth: Float, color: Color) {

    val width = rect.width
    val height = rect.height
    val gridWidth = width / 3
    val gridHeight = height / 3

    // Horizontal lines
    for (i in 1..2) {
        drawLine(
            color = color,
            start = Offset(rect.left, rect.top + i * gridHeight),
            end = Offset(rect.right, rect.top + i * gridHeight),
            strokeWidth = strokeWidth
        )
    }

    // Vertical lines
    for (i in 1..2) {
        drawLine(
            color,
            start = Offset(rect.left + i * gridWidth, rect.top),
            end = Offset(rect.left + i * gridWidth, rect.bottom),
            strokeWidth = strokeWidth
        )
    }
}